﻿using System;
using System.Collections.Generic;
using xn;

namespace KinectAPI.Gestures
{
    public class MoveRight : Gesture
    {
        private BodyTracker body;
        private BodyGestureGenerator bgg;
        private Dictionary<uint, LinkedList<Point3D>> users;
        int LineSize = 10;

        public event EventHandler Start;

        public event EventHandler End;

        public event EventHandler Recognised;

        #region Constructor

        public MoveRight()
        {
        }

        public void construct(object[] args)
        {
            bgg = (BodyGestureGenerator)args[1];
            body = (BodyTracker)args[0];
            body.UsersUpdated += new BodyTracker.UsersUpdatedHandler(Users_Updated);

            users = new Dictionary<uint, LinkedList<Point3D>>();
        }

        #endregion

        public string getName()
        {
            return "MoveRight";
        }

        #region Event Handler

        void Users_Updated(object sender, UsersEventArgs e)
        {
            foreach (var user in e.users)
            {
                if (!users.ContainsKey(user.Id))
                {
                    users.Add(user.Id, new LinkedList<Point3D>());
                }

                LinkedList<Point3D> points = users[user.Id];
                if (points.Count == 10)
                {
                    points.RemoveFirst();
                }
                points.AddLast(new Point3D(user.RightHand.X, user.RightHand.Y, user.RightHand.Z));

                if (DetectMvtV(points))
                {
                    points.Clear();
                    Recognised(this, new GestureEventArgs(getName(), null));
                }
            }
        }

        #endregion

        public bool DetectMvtV(LinkedList<Point3D> points)
        {
            int MinXDelta = 200; // required vertical distance
            int MaxYDelta = 100; // max mount of horizontal variation

            if (points.Count < LineSize)
            {
                return false;
            }

            float x1 = points.First.Value.X;
            float y1 = points.First.Value.Y;
            float x2 = points.Last.Value.X;
            float y2 = points.Last.Value.Y;

            //We check the both x: first and last
            if (x1 - x2 < MinXDelta)
            {
                return false;
            }

            //We check the both y: first and last
            if (y1 - y2 > MaxYDelta)
            {
                return false;
            }

            LinkedListNode<Point3D> pointNode = points.First;

            for (int i = 1; i < LineSize - 2; i++)
            {
                pointNode = pointNode.Next;
                Point3D point = pointNode.Value;
                //We check the interval/delta on the Y-axis if it was not reached
                if (Math.Abs((point.Y - y1)) > MaxYDelta)
                {
                    return false;
                }

                float result =
                    (y2 - y1) * point.X +
                    (x2 - x1) * point.Y +
                    (x1 * y2 - x2 * y1);

                if (result > Math.Abs(result)) //We check the absolute value of result
                {
                    return false;
                }
            }
            return true;
        }
    }
}
